﻿/// <reference name="MicrosoftAjax.js"/>
/// <reference path="/WebUI/core.debug.js" />

//模版绑定技术
Type.registerNamespace("Doo");

Doo.TemplateBinder = function (context) {
    this.context = context;
    this.tpls = {};
    this.cmtpls = {};
    this.__handlerList = new Sys.EventHandlerList();


    Doo.Scripts.SetEvents(this, { "domready": 0, "ready": 0 });

}

//模板编译器
Doo.TemplateBinder.Compiler =
(function () {
    var throwErr = function (str) {
        throw new Error("错误的表达式：" + str);
    };
    var bindExpC = function (str) {
        ///<summary>编译绑定表达式（语法：[prop][[?obj1:obj2]|[||objempty]][,format]）。传入的是不包含#的字符串</summary>
        ///<param name="str" type="String">绑定表达式，不包含#</param>
        ///<returns type="Array">编译后的数组</returns>
        //1.辨识?和||
        var len = str.length;
        var IIF = str.indexOf('?');
        var OR = str.indexOf('|');
        var FORMAT = str.indexOf(',');
        if (FORMAT < 0) FORMAT = len;
        var data = [null];
        var propEnd = len;
        if (IIF >= 0) {
            //属于IIF的领地
            propEnd = IIF;
            var THEN = str.indexOf(':', IIF + 1);
            if (THEN < 0 || FORMAT < THEN) {
                throwErr('#' + str);
            }
            if (IIF > 0) data[0] = str.substring(0, IIF);
            data.push('?');
            data.push(str.substring(IIF + 1, THEN));
            data.push(str.substring(THEN + 1, FORMAT));
        }
        else if (OR >= 0 && OR < len - 1 && str.charAt(OR + 1) == '|') {
            propEnd = OR;
            if (FORMAT < OR) {
                throwErr('#' + str);
            }
            if (OR > 0) data[0] = str.substring(0, OR);
            data.push('|');
            data.push(str.substring(OR + 2, FORMAT));
        }
        else {
            data[0] = str.substring(0, FORMAT);
            data.push(null);
        }
        if (FORMAT < len - 1) {
            data.push(str.substr(FORMAT + 1));
        };
        if (data[0] && data[0].indexOf('.') > 0) {//可能是多id
            data[0] = [data[0], data[0].split('.')];
        }
        return data;
    };
    var tplExpC = function (str) {
        ///<summary>编译模板表达式，语法[tplid]|[#exp]|[%exp]</summary>
        ///<param name="str" type="String">表达式，提示，此处的数据上下文为其后的表达式</param>
        ///<returns type="Array">编译后的数组</returns>
        var c = str.charAt(0);
        var data = [c];
        if (c == '#') {
            data.push(bindExpC(str.substr(1)));
        }
        else if (c == '%') {
            data.push(str.substr(1));
        }
        else {
            data[0] = null;
            data.push(str);
        }
        return data;
    };
    var replaceStr = function (str) {
        return str.replace(/(\*?{\*?)|(}\*)/g, function (v) { return v.indexOf('{') >= 0 ? "{" : "}"; });
    };

    return function (tpl, binder) {
        ///<summary>编译模板</summary>
        ///<param name="tpl" type="String"></param>
        ///<param name="binder" type="Doo.TemplateBinder"></param>
        var i = 0, cmdtype;
        var cmtpl = new Array();
        var s = 0; //保存已处理的字符串位置
        while (i < tpl.length) {
            var st = tpl.indexOf('{', i);
            if (st < 0) {
                cmtpl.push(replaceStr(tpl.substring(s, tpl.length + 1)));
                break;
            }
            if (st > 0 && tpl.charAt(st - 1) == '*') {
                i = st + 1;
                continue;
            }

            if ((cmdtype = tpl.charAt(st + 1)).match(/[[$#%]/) == null) {
                i = st + 1;
                continue;
            }
            var en = tpl.indexOf('}', st + 1);
            while (tpl.charAt(en + 1) == '*') {
                en = tpl.indexOf('}', en + 2);
            }

            if (st > s) { cmtpl.push(replaceStr(tpl.substring(s, st))); } //加入纯字符串，不包括最后的{
            //分析brace
            var tplid = null;
            var brace = replaceStr(tpl.substring(st + 1, en));

            var cmdi = 0;
            if (cmdtype == '[') {
                cmdi = brace.indexOf(']', 1);
                if (cmdi < 0) throw new Error("错误的模板ID" + brace);
                tplid = brace.substring(1, cmdi);
                tplid = tplExpC(tplid);
                brace = brace.substring(cmdi + 1, brace.length + 1);
                cmdtype = brace.charAt(0);
            }

            var cmdvalue = brace.substring(1, brace.length);
            if (cmdtype == '#') {
                //prop,format
                cmdvalue = bindExpC(cmdvalue);
            }
            else if (cmdtype == '$') {
                //表达式语法：$cmd,xxx,#xxx,>#xxx
                //传递的总是字符串
                var mh = cmdvalue.indexOf(':');
                var ex = new Array(mh < 0 ? cmdvalue : cmdvalue.substring(0, mh)); //ex:[name,value]
                var args = mh < 0 ? null : cmdvalue.substring(mh + 1, cmdvalue.length + 1).split(',');
                var exn = ex[0];
                var expbuilder = (binder && binder.expressBuilder && binder.expressBuilder[exn]) || Doo.TemplateBinder.Compiler.ExpressionBuilder[exn];
                if (!expbuilder) throw new Error("不存在名为" + exn + "的表达式生成器，表达式的正确使用形式为$expname:arg1,arg2,...,argn");
                cmdvalue = expbuilder(args);
            }
            cmtpl.push(new Array(cmdtype, cmdvalue, tplid)); //加入数组形式的命令:[cmdtype,cmdvalue,tplid]

            i = en + 1;
            s = i;
        }
        return cmtpl;
    }
})();

Doo.TemplateBinder.Compiler.ExpressionBuilder =
{
    ///表达式生成器
    ///返回字符串表示生成静态字符串
    ///返回function表示生成时执行该function.
    'event': function (args) {
        ///<summary>事件触发脚本生成器</summary>
        return function (binder) { return Doo.TemplateBinder.Plugin.Event.get_trigscript(binder, args); };
    },
    'pager': function (propname) {
        ///<summary>分页设置表达式</summary>
        return function (binder) { return Doo.TemplateBinder.Plugin.Pager.setpager(binder, propname); };
    },
    'ctl': function (args) {
        ///<summary>控件生成</summary>
        ///<param type="String" name="args">参数，格式为id</param>
        return function (binder) { return Doo.TemplateBinder.Plugin.Control.processcontrol(binder, args[0]); };
    },
    'element': function (args) {
        ///<summary>html元素生成</summary>
        ///<param type="String" name="args">参数，格式为id</param>
        return function (binder) { return Doo.TemplateBinder.Plugin.Control.processcontrol(binder, args[0], true); };
    },
    'tagns': function (args) {
        ///<summary>控件域注册器</summary>
        ///<param type="String" name="args">参数，格式为scope,namespace</param>
        return function () { var ct = Doo.ControlTag; if (!ct[args[0]]) ct[args[0]] = [args[1], {}]; };
    },
    'tagname': function (args) {
        ///<summary>控件名转换器</summary>
        ///<param type="String" name="args">参数，格式为scope,tagname,ctltype</param>
        return function () { var ns = Doo.ControlTag[args[0]]; if (!ns[1][args[1]]) ns[1][args[1]] = args[2]; };
    }
}
Doo.TemplateBinder.Plugin = {};
Doo.TemplateBinder.Plugin.Event = {//事件插件
    processargs: function (binder, args) {//分析参数
        var dataitem = binder.dataItem;
        var newargs = new Array();
        for (var i = 0; i < args.length; i++) {
            if (args[i].charAt(0) != '#') { newargs.push(args[i]); continue; }

            var prop = args[i].substr(1);
            newargs.push(prop ? dataitem[prop] : dataitem);
        }
        return newargs;
    },
    get_trigscript: function (binder, args) {//得到脚本
        var context = binder.context;
        if (!context.tpleventargs) context.tpleventargs = [];
        var argindex = context.tpleventargs.length;
        context.tpleventargs.push(this.processargs(binder, args));
        return String.format('$items.get({0}).trig_tplevent(event,{1},this);', context.index, argindex);
    }
};
Doo.TemplateBinder.Plugin.Pager = {//分页插件
    setpager: function (binder, prop) {
        var recordcount = binder.dataItem[prop];
        var pager = binder.context.get_pager();
        if (!pager) return;
        pager.set_recordcount(recordcount);
        pager.render();
    } //刷新pager
};
Doo.TemplateBinder.Plugin.Control = {//控件生成
    __maxid: 0,
    newid: function () {
        return "__doo__" + this.__maxid++;
    },
    /*delegatea: function (ctl, element) {
    ///<summary>确保domready事件中会调用自己以创建控件</summary>
    ///<param type="Doo.ControlBase" name="ctl"></param>
    var c = ctl['__tplcontrol'];
    if (c instanceof Array) {
    ctl.beginCreateChilds();
    //1.创建
    var v = ctl.newAsync();
    for (var i = 0; i < c.length; i++) {
    var d = c[i];
    var domid = d[0];
    var ctlid = d[1];
    var dataitem = d[2];
    var domelement = $get(domid);
    ctl.beginCreateChilds();

    if (d[3]) {//d[3]---IsElement是否是html元素而不是控件
    domelement.ctlid = ctlid;
    domelement.__dataitem = dataitem;
    Doo.ControlLoader.controlCreated(domelement, domelement);
    ctl.addChild(domelement);
    ctl.endCreateChilds();
    }
    else {
    $ctl(domelement, function (contrl, cid) {
    if (!ctl.checkAsync(v)) return;
    contrl.ctlid = cid;
    ctl.addChild(contrl);
    ctl.endCreateChilds();
    }, null, { __dataitem: dataitem }, ctl, ctlid);
    }
    }

    //2.清理
    ctl['__tplcontrol'].length = 0;

    ctl.endCreateChilds();
    }
    else {
    throw new Error("无效的生成");
    }
    },*/
    delegatea: function (binder, frag) {
        ///<summary>确保domready事件中会调用自己以创建控件</summary>
        ///<param type="Doo.TemplateBinder" name="binder"></param>
        var c = binder['__tplcontrol'];
        var ctl = binder.context;
        var iscontextctl = ctl.addChild ? true : false;

        if (iscontextctl && !ctl.checkAsync(binder['__asyncver'])) return; //同步状态失败，可能是已中止加载
        if (c instanceof Array) {
            //ctl.beginCreateChilds();
            binder.beginLock();
            //1.创建
            var v = iscontextctl && ctl.get_asyncver(); //由于会出现多个区域同时对ctl操作的情况，此处不再设置新同步状态
            for (var i = 0; i < c.length; i++) {
                var d = c[i];
                var domid = d[0];
                var ctlid = d[1];
                var dataitem = d[2];
                var domelement = frag.getElementById ? frag.getElementById(domid) : frag.querySelector("#" + domid);
                //ctl.beginCreateChilds();
                binder.beginLock();

                if (d[3]) {//d[3]---IsElement是否是html元素而不是控件
                    domelement.ctlid = ctlid;
                    domelement.__dataitem = dataitem;
                    domelement.__scope = ctl;
                    Doo.ControlLoader.controlCreated(domelement, domelement);
                    if (iscontextctl) ctl.addChild(domelement);
                    binder.endLock();
                    //ctl.endCreateChilds();
                }
                else {
                    $ctl(domelement, function (contrl, cid) {
                        if (iscontextctl && !ctl.checkAsync(v)) return;
                        contrl.ctlid = cid;
                        if (iscontextctl) ctl.addChild(contrl);
                        //ctl.endCreateChilds();
                        binder.endLock();
                    }, null, { __dataitem: dataitem }, ctl, ctlid);
                }
            }

            //2.清理
            binder['__tplcontrol'].length = 0;
            binder.endLock();
        }
        else {
            throw new Error("无效的生成");
        }
    },
    ensureEventReg: function (binder) {
        ///<summary>确保domready事件中会调用自己以创建控件</summary>
        ///<param type="Doo.DataViewBase" name="context"></param>
        if (binder['__tplcontroleventreg']) return;
        binder['__tplcontroleventreg'] = true;
        binder['__tplcontrol'] = new Array();
        var context = binder.context;
        binder['__asyncver'] = context.get_asyncver ? context.get_asyncver() : 0;
        binder.add_domready(this.delegatea);
    },
    processcontrol: function (binder, id, iselement) {
        ///<summary>处理control表达式，向添加内容</summary>
        ///<param type="Doo.TemplateBinder" name="binder"></param>
        ///<param type="String" name="id"></param>
        ///<param type="Boolean" name="iselement">是否仅是html元素</param>
        var context = binder.context;
        this.ensureEventReg(binder);
        var domid = this.newid();
        binder['__tplcontrol'].push([domid, id, binder.dataItem, iselement]);
        return domid;
    }
};

Doo.TemplateBinder.LoadTpl = {
    load: function (url, TemplateBinder) {
        TemplateBinder.istplready = false;
        TemplateBinder.loadingurl = url;

        var ishtml = url.endsWith("#htm");
        var request = new Sys.Net.WebRequest();
        request.set_url(ishtml ? (url.substring(0, url.length - 4)) : url);
        request.add_completed(Doo.TemplateBinder.LoadTpl._loadok);
        request.set_userContext({ loadingurl: url, binder: TemplateBinder, ishtml: ishtml });
        request.invoke();
    },
    _loadok: function (response) {
        var context = response.get_webRequest().get_userContext();
        var tplbinder = context.binder;
        if (context.loadingurl != tplbinder.loadingurl) return; //目标载入页已更改，则放弃
        tplbinder.cmtpls = [];

        if (!context.ishtml) {
            var xml = response.get_xml();
            if (xml == null) {
                tplbinder.context.set_html(Doo.Resource.TemplateLoadFail);
                return;
            }

            var tpls = xml.getElementsByTagName("template");

            for (var i = 0; i < tpls.length; i++) {
                var id = tpls[i].getAttribute('id');
                var tpl = tpls[i].text;
                tplbinder.tpls[id] = tpl;
            }
        }
        else {
            tplbinder.tpls['root'] = response.get_responseData();
        };

        tplbinder.istplready = true;
        if (tplbinder.ontplready != null) {
            tplbinder.ontplready();
        }
    }
};

Doo.TemplateBinder.prototype = {
    context: null, ///上下文环境
    istplready: true, ///模板是否可用
    tpls: null, ///没有编译的模板
    cmtpls: null, ///已经编译的模板
    roottplid: 'root', ///根模板ID
    ontplready: null,

    set_tpl: function (id, tpl) {
        this.tpls[id] = tpl;
        this.cmtpls[id] = null;
    },
    set_tpls: function (tpls) {
        this.tpls = tpls;
        this.cmtpls = {};
    },
    expressBuilder: {},
    get_cmtpl: function (tplid) {
        var cmtpl = this.cmtpls[tplid];
        if (cmtpl) return cmtpl;

        var tpl = this.tpls[tplid];
        if (!tpl) throw new Error("Error TemplateID:" + tplid);

        this.cmtpls[tplid] = Doo.TemplateBinder.Compiler(tpl, this);

        return this.cmtpls[tplid];
    },

    _bindtrack: null, ///绑定深度

    dataItem: null, //当前数据项

    _bindcmd: (function () {

        var bindExpR = function (dataitem, cmd) {
            var d = cmd[0];
            var result = (d == null || d.length == 0) ? dataitem : ((d instanceof Array) ? (function (a, b) {
                if (a[0] in b) return b[a[0]];
                for (var i = 0; i < a[1].length; i++) b = b[a[1][i]];
                return b;
            })(d, dataitem) : dataitem[d]);
            var i = 2;
            var t = cmd[1];
            if (t == '?') {
                result = Doo.TemplateBinder.Executor.QuickFunc.isempty(result) ? cmd[3] : cmd[2];
                i += 2;
            }
            else if (t == '|') {
                if (Doo.TemplateBinder.Executor.QuickFunc.isempty(result)) result = cmd[2];
                i++;
            }
            if (cmd[i]) {//有格式字符串
                result = String.format("{0:" + cmd[i] + "}", result);
            }
            return result;
        };

        return function (type, cmd, tplid, builder) {
            ///<summary>处理命令</summary>
            var result = null;
            var DataItem = this.dataItem;
            if (DataItem == null) return;

            if (type == '%') {
                result = Doo.TemplateBinder.Executor.Eval.call(this, cmd, DataItem);
            }
            else if (type == '#') {//目前分有无格式化字符串
                result = bindExpR(DataItem, cmd);
            }
            else if (type == '$') {
                if (typeof (cmd) == 'function') {
                    result = cmd(this);
                }
                else {
                    result = cmd;
                }
            }

            if (!tplid) {
                builder.push(result);
                return;
            }
            var c = tplid[0];
            if (c == null) {
                tplid = tplid[1];
            }
            else if (c == '%')//%
                tplid = Doo.TemplateBinder.Executor.Eval.call(this, tplid[1], DataItem);
            else if (c == '#') {//#
                tplid = bindExpR(result, tplid[1]);
            }

            if (!tplid) return;
            var cmtpl = this.get_cmtpl(tplid);
            return this._bindtpl(result, cmtpl, builder);
        }
    })(),

    _bindfunc: function (index, data, cmtpl, builder) {
        this._bindtrack.push(index);
        this.dataItem = data;
        for (var i = 0; i < cmtpl.length; i++) {
            var cmd = cmtpl[i];
            if (typeof (cmd) == 'string') builder.push(cmd);
            else {
                this._bindcmd(cmd[0], cmd[1], cmd[2], builder);
            }
        };
        this._bindtrack.pop();
    },

    _bindtpl: function (data, cmtpl, builder) {
        ///<summary>使用生成器和模板绑定数据</summary>
        var olddataitem = this.dataItem;

        if (data && Array.isInstanceOfType(data)) {
            for (var di = 0; di < data.length; di++) {
                this._bindfunc(di, data[di], cmtpl, builder);
            }
        }
        else {
            this._bindfunc(0, data, cmtpl, builder);
        }
        //绑定完毕
        this.dataItem = olddataitem; //恢复dataItem
        return '';
    },

    __handlerList: null,

    _lock: 0,
    beginLock: function () {
        this._lock++;
    },
    endLock: function () {
        this._lock--;
        if (this._lock == 0) {
            this.onready(this);
        }
    },

    bind: function (data, tplid) {
        ///<summary>使用模板绑定数据</summary>
        if (!tplid) tplid = this.roottplid;
        var builder = new Array();
        this._bindtrack = new Doo.TemplateBinder.Executor.Track();
        this._bindtpl(data, this.get_cmtpl(tplid), builder);
        this._bindtrack = null;
        return builder.join('');
    },

    bindEx: function (data, tplid, callback) {
        ///<summary>使用模版绑定数据，并生成控件。使用callback接收创建好的文档碎片</summary>
        var html = this.bind(data, tplid);
        var delegate = Function.createDelegate(this, function (frag) {
            ///<param name="frag" type="HtmlFragment"></param>
            var ready = function (binder) {
                binder.remove_ready(ready);
                callback(frag);
            };
            this.add_ready(ready);
            this.beginLock();
            Doo.ControlLoader.createChilds(frag.childNodes, this.context, this);
            this.ondomready(this, frag);
            this.endLock();
        });
        this['__tplcontroleventreg'] = false;
        Doo.Utils.Dom.createElement(html, delegate);
    }
}

Doo.TemplateBinder.Bind = function (context, cmtpls, data) {
    ///<summary>使用模版技术绑定数据，传递已编译的模版</summary>
    var tplBinder = new Doo.TemplateBinder(context);
    tplBinder.cmtpls = cmtpls;
    return tplBinder.bind(data);
}
Doo.TemplateBinder.BindEx = function (context, cmtpls, data, callback) {
    ///<summary>使用模版技术绑定数据，传递已编译的模版</summary>
    var tplBinder = new Doo.TemplateBinder(context);
    tplBinder.cmtpls = cmtpls;
    return tplBinder.bindEx(data, null, callback);
}
Doo.TemplateBinder.Executor = //执行器
{
QuickFunc: {
    ///<summary>绑定时可用的方法</summary>
    isempty: function (obj) {
        if (obj == null) return true;
        if (obj == '') return true;
        if (obj.length && obj.length == 0) return true;
        return false;
    }
},
CachedCmd: {},
Eval: function (cmd, dataitem) {
    ///<summary>用于在特定环境下执行语句</summary>
    //此处用with的原因是为了AjaxMin不会压缩此处的变量
    with (Doo.TemplateBinder.Executor.QuickFunc) {
        var DataItem = d$ = dataitem;
        return eval(cmd);
    }
}
}

Doo.TemplateBinder.Executor.Track = function () { };
Doo.TemplateBinder.Executor.Track.prototype =
{
    ///堆栈
    _track: new Array(),
    push: function (v) { this._track.push(v); },
    pop: function () { this._track.pop(); },
    toString: function () { return this._track.join(','); }
}

Doo.TemplateBinder.registerClass("Doo.TemplateBinder");
$binder = (function () {
    var cmtpls = {};
    var binder = new Doo.TemplateBinder(window);
    var ensurefunc = function (tpl) {
        var cmtpl;
        if (!(tpl in cmtpls)) {
            cmtpl = Doo.TemplateBinder.Compiler(tpl);
            cmtpls[tpl] = cmtpl;
        }
        else {
            cmtpl = cmtpls[tpl];
        };
        binder.cmtpls['root'] = cmtpl;

    };
    var bindfunc = function (tpl, data) {
        ensurefunc(tpl);
        return binder.bind(data);
    };
    var bindexfunc = function (tpl, data, callback, context) {
        ensurefunc(tpl);
        binder.context = context || $Page;
        binder.bindEx(data, null, callback);
    };
    return { _binder: binder, bind: bindfunc, bindEx: bindexfunc };
})();

Doo.DataViewBase = function (element) {
    this._templatebinder = new Doo.TemplateBinder(this);

    Doo.DataViewBase.initializeBase(this, [element]);
}

Doo.DataViewBase.prototype =
{
    _templatebinder: null,

    /* 编译模版 */
    get_cmtpl: function (name) {
        /// <returns type="Array"></returns> 
        return this._templatebinder.get_cmtpl(name);
    },


    /* 设置内部HTML */
    set_html: function (html) {
        this.get_element().innerHTML = html;
    },
    set_htmlAsync: function (html, callback) {
        Doo.Utils.Dom.setHtmlAsync(this.get_element(), html, callback);
    },
    /* 关联的分页控件 */
    pagerid: null,
    pager: null,
    _pagerHandler: null,
    get_pager: function () {
        /// <returns type="Doo.Pager"></returns> 
        return this.pager;
    },
    set_pager: function (pager) {
        var lv = this;
        if (lv.pager == pager) return;
        if (lv.pager && lv._pagerHandler) { pager.remove_pageindexchange(lv._pagerHandler); };
        lv.pager = pager;
        var changed = function (pager) { lv.pagerchanging(pager); };
        pager.add_pageindexchange(changed);
        lv._pagerHandler = changed;
    },
    pagerchanging: function (pager) {//当分页改变时
        this._fetchdata();
    },

    /* 关联的数据源 */
    datasourceid: null,
    datasource: null,
    set_datasource: function (v) { this.datasource = v; },
    get_datasource: function () {
        /// <returns type="Doo.DataSource.Base"></returns> 
        return this.datasource;
    },

    _fetchdata: function () {

        var args = {};
        var pager = this.get_pager();
        if (pager != null) {
            args.rowstart = pager.get_rowstart();
            args.rowcount = pager.get_rowcount();
        }

        this.ondatafetching(this, args);

        if (this.datasource == null) return;
        var onsucc = function (result, userContext) { userContext.lv.databind(result); };
        this.datasource.Select(onsucc, function (err) { alert(err.get_message()); }, { args: args }, { lv: this });
    },

    initialize: function () {
        Doo.DataViewBase.callBaseMethod(this, 'initialize');

        var ts = this;
        this.load_handler = function () { ts.load(); }
        Sys.Application.add_load(this.load_handler);
    },

    autobind: true,
    set_autobind: function (v) {
        this.autobind = ((v == "true")
        || v == "TRUE"
        || v) ? true : false;
    },
    get_autobind: function () {
        return this.autobind;
    },

    load_handler: null,
    onload: null, //由框架赋值
    load: function () {
        if (this.load_handler) {
            Sys.Application.remove_load(this.load_handler);
            this.load_handler = null;
        }

        this.ensurebind();

        if (this.onload) this.onload(this, null);

        if (this.datasource && this.autobind) {
            //如果有数据源，则开始获取数据
            this._fetchdata();
        }
    },

    ensurebind: function () {
        ///<summary>确定绑定环境</summary>
        var s = this.get_scripts();
        var hc = s && s.findChild;

        if (this.datasourceid && !this.datasource) {
            this.datasource = (hc && s.findChild(this.datasourceid)) || $get(this.datasourceid).control;
        }

        //select..
        if (this.pagerid && !this.pager) {
            this.pager = (hc && s.findChild(this.pagerid)) || $get(this.pagerid).control;
            var lv = this;
            var changed = function (pager) { lv.pagerchanging(pager); };
            this.pager.add_pageindexchange(changed);
            this._pagerHandler = changed;
        }
    },

    _bindeddata: null,

    databind: function (data) {
        ///<summary>数据绑定，如果没有传入就使用数据源</summary>
        if (arguments.length < 1) {
            if (!this.datasource || (!this.pager && this.pagerid)) this.ensurebind();
            if (!this.datasource) return; //没有数据源就直接返回
            this._fetchdata();
        }

        this['__bindings'] = null; //重置绑定字段
        this.clearChilds(); //清除所有的子控件

        var bindingArgs = { data: data };
        this.ondatabinding(bindingArgs);
        data = bindingArgs.data;

        var v = this.newAsync();
        this._templatebinder.bindEx(data, null, Function.createDelegate(this, function (frag) {
            if (!this.checkAsync(v)) return; //未通过同步检查
            this._bindeddata = data;
            var e = this.get_element();
            e.innerHTML = "";
            e.appendChild(frag);
            this.ondomready(this, e);
            this.ondatabound(this, data);
        })
            );
    }
}

//datafetching开始获取数据
//databinding数据已获取，准备绑定数据
//databound数据已绑定，且Dom树及控件已生成或已在异步生成中。可以结合isChildsReady和ChildsReady事件在需要子控件的情况
//domready数据绑定，Dom树已生成，但树上控件还未生成
Doo.Scripts.SetEvents(Doo.DataViewBase.prototype, ["datafetching", "databinding", "databound", "domready"]);

Doo.DataViewBase.registerClass('Doo.DataViewBase', Doo.ControlBase);